#define ALFA_MAX 5
#include <math.h>

double bisection(OptimFunc of, int n, double*x, double*d, double minAlfa, double maxAlfa, int maxIter){
    double a,b,mid,ga,gb,gmid;
    int i;
    a = minAlfa;	// blizszy alfa
    ga = directedG(of,n,x,d,a);

    b = maxAlfa;	// dalszy alfa
    gb = directedG(of,n,x,d,b);

    mid = a;          //default
    if (ga >= 0){
        return a;
    }
    for (i=0; i<maxIter; ++i){
        mid = a + (b-a)/2;
        gmid = directedG(of,n,x,d,mid);
        if (gmid<0){
            a = mid;
            ga = gmid;
        } else if (gmid>0){
            b = mid;
            gb = gmid;
        } else {
            return mid;
        }

    }
    return mid;
}


/*
zoom
*/
double zoom(OptimFunc of, int n, double*x, double*d, double a_low, double a_hi, double c1, double c2, int maxIter ){

	double alfa,fi_ai,fi,fi_prim_zero,fi_a_low,fi_prim;
	int i;
	for(i=0;i<maxIter;++i){
        alfa = bisection(of,n,x,d,a_low,a_hi,maxIter); //alfa_j
        //Evaluate fi_aj
        fi_ai = directedF(of,n,x,d,alfa);

        fi = directedF(of,n,x,d,0); //fi_0
        fi_prim_zero = directedG(of,n,x,d,0); //fi_prim_zero
        fi_a_low=directedF(of,n,x,d,a_low);

        if( (fi_ai > (fi +  c1*alfa*fi_prim_zero)) || (fi_ai>=fi_a_low) ){
        a_hi=alfa;
        }
        else{
            //evaluate fi_prim_aj
            fi_prim	 =directedG(of,n,x,d,alfa);
            if( abs(fi_prim)<=(-c2*fi_prim_zero) )
                return alfa;

            if(fi_prim*(a_hi-a_low) >= 0)
                a_hi=a_low;

            a_low=alfa;

        }
	}

	return alfa; // zmiana pętli while na for


}
///


/*
    kryterium Wolfa
    szukanie alfa
*/
double wolfe(OptimFunc of, int n, double*x, double*d, double maxAlfa, int maxIter){
	double alfa_prev=0;
	double alfa=1;
	double alfa_gwiazdka;
	double fi_ai,fi,fi_prim,fi_a_prev,fi_prim_zero;
	double c1=0.00001;
	double c2=0.3;
	int i=1;
	int j;


	for(j=0;j<maxIter;++j){

	fi_ai=directedF(of,n,x,d,alfa);
	fi=directedF(of,n,x,d,0);
	fi_a_prev=directedF(of,n,x,d,alfa_prev);
	fi_prim_zero=directedG(of,n,x,d,0);

	if( fi_ai > (fi + c1*alfa*fi_prim_zero) || (fi_ai >= fi_a_prev && i>1 ) ){
		alfa_gwiazdka = zoom(of,n,x,d,alfa_prev,alfa,c1,c2,maxIter);
		return alfa_gwiazdka;
		}

	//Evaluate fi_prim(alfa)
	fi_prim	 =directedG(of,n,x,d,alfa);

	if(abs(fi_prim)<= -c2*fi_prim_zero){
		alfa_gwiazdka=alfa;
		return alfa_gwiazdka;
		}

	if(fi_prim >= 0){
		alfa_gwiazdka=zoom(of,n,x,d,alfa,alfa_prev,c1,c2,maxIter);
		return alfa_gwiazdka;
		}

	//Choose alfa from (alfa,alfa_max)
	alfa=(alfa+maxAlfa)/2;
	i++;
    }//for
    return alfa;
}
///

/*
    metoda przepolowienia przedzialu
*/
double findAlfaBisection(OptimFunc of, int n, double*x, double*d, double maxAlfa, int maxIter){
    double a,b,mid,ga,gb,gmid;
    int i;
    a = 0;          // blizszy alfa
    ga = directedG(of,n,x,d,a);
    //printf("findAlfa a:%g = [%g]\n", a, ga);
    b = maxAlfa;    // dalszy alfa
    gb = directedG(of,n,x,d,b);
    //printf("findAlfa b:%g = [%g]\n", b, gb);
    mid = a;          //default
    if (ga >= 0){
        printf("minimum found, ga = %g \n", ga);
        return 0.0;
    }
    for (i=0; i<maxIter; ++i){
        mid = a + (b-a)/2;
        gmid = directedG(of,n,x,d,mid);
        if (gmid<0){
            a = mid;
            ga = gmid;
        } else if (gmid>0){
            b = mid;
            gb = gmid;
        } else {
            return mid;
        }
//        printf("findAlfa mid:%g = [%g]\n", mid, gmid);
    }
    return mid;
}

